package tech.eyao.hs60x.utils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Throwables;

import io.netty.handler.codec.http.HttpUtil;

/**
 * 
 * 类HttpClientUtil.java的实现描述：TODO 类实现描述 
 * @author fengjianchao 2018年1月16日 下午10:10:18
 */
public class HttpClientUtil {

    private static final String CHARSET = "UTF-8";

    private static final Logger LOG     = LoggerFactory.getLogger(HttpUtil.class);

    @SuppressWarnings("deprecation")
    private static CloseableHttpClient createSSLClientDefault() {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                //信任所有
                @Override
                public boolean isTrusted(java.security.cert.X509Certificate[] chain, String authType)
                        throws java.security.cert.CertificateException {
                    return true;
                }

            }).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            return HttpClients.custom().setSSLSocketFactory(sslsf).build();
        } catch (Exception e) {
            LOG.warn("获取https错误:{}", Throwables.getStackTraceAsString(e));
        }
        return HttpClients.createDefault();
    }

    /**
     * 需要额外添加header信息Get请求
     * 
     * @param url
     * @param params
     * @param header
     * @return
     */
    public static String get(String url, Map<String, String> params, Map<String, String> header) {
        return doGet(url, params, CHARSET, header);
    }

    public static String post(String url, Map<String, String> params, Map<String, String> header) {
        return doPost(url, params, header, CHARSET);
    }

    public static String post(String url, String params, Map<String, String> header) {
        return doPost(url, params, header, CHARSET);
    }

    /**
     * HTTP Get 获取内容
     * 
     * @param url 请求的url地址 ?之前的地址
     * @param params 请求的参数
     * @param charset 编码格式
     * @return 页面内容
     */
    private static String doGet(String url, Map<String, String> params, String charset, Map<String, String> header) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        CloseableHttpClient httpClient = getClientByUrl(url);
        CloseableHttpResponse response = null;
        try {
            if (params != null && !params.isEmpty()) {
                List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    String value = entry.getValue();
                    if (value != null) {
                        pairs.add(new BasicNameValuePair(entry.getKey(), value));
                    }
                }
                url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
            }
            HttpGet httpGet = new HttpGet(url);
            //如果有请求头参数，添加进header中
            if (null != header && !header.isEmpty()) {
                for (String key : header.keySet()) {
                    httpGet.addHeader(key, header.get(key));
                }
            }
            response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpGet.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, charset);
            }
            EntityUtils.consume(entity);
            return result;
        } catch (Exception e) {
            LOG.warn("发送请求失败:{}", Throwables.getStackTraceAsString(e));
        } finally {
            closeResponse(response);
            closeHttpClient(httpClient);
        }
        return null;
    }
    
    /**
     * HTTP Get 获取内容(根据http statusCode做详细的处理)，主要对statusCode>=500的做处理
     * 
     * @param url 请求的url地址 ?之前的地址
     * @param params 请求的参数
     * @param charset 编码格式
     * @return 页面内容
     */
    public static String doGetForMoreStatus(String url, Map<String, String> params, String charset,
                                             Map<String, String> header) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        CloseableHttpClient httpClient = getClientByUrl(url);
        CloseableHttpResponse response = null;
        try {
            if (params != null && !params.isEmpty()) {
                List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    String value = entry.getValue();
                    if (value != null) {
                        pairs.add(new BasicNameValuePair(entry.getKey(), value));
                    }
                }
                url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
            }
            HttpGet httpGet = new HttpGet(url);
            //如果有请求头参数，添加进header中
            if (null != header && !header.isEmpty()) {
                for (String key : header.keySet()) {
                    httpGet.addHeader(key, header.get(key));
                }
            }
            response = httpClient.execute(httpGet);
            String result = null;
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode >= 400 && statusCode < 500) {
                httpGet.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            //如果服务器返回是5xx，放过去
            if (statusCode >= 500) {
                JSONObject json = new JSONObject();
                json.put("code", "200");
                json.put("result", "true");
                result = json.toString();
            }
            if (statusCode == 200) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    result = EntityUtils.toString(entity, charset);
                }
                EntityUtils.consume(entity);
                return result;
            }
            return result;
        } catch (Exception e) {
            LOG.warn("发送请求失败:{}", Throwables.getStackTraceAsString(e));
        } finally {
            closeResponse(response);
            closeHttpClient(httpClient);
        }
        return null;
    }

    /**
     * HTTP Post 获取内容
     * 
     * @param url 请求的url地址 ?之前的地址
     * @param params 请求的参数
     * @param charset 编码格式
     * @return 页面内容
     */
    private static String doPost(String url, Map<String, String> params, Map<String, String> header, String charset) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        CloseableHttpClient httpClient = getClientByUrl(url);
        CloseableHttpResponse response = null;
        try {
            List<NameValuePair> pairs = null;
            if (params != null && !params.isEmpty()) {
                pairs = new ArrayList<NameValuePair>(params.size());
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    String value = entry.getValue();
                    if (value != null) {
                        pairs.add(new BasicNameValuePair(entry.getKey(), value));
                    }
                }
            }
            HttpPost httpPost = new HttpPost(url);
            //如果有请求头参数，添加进header中
            if (null != header && !header.isEmpty()) {
                for (String key : header.keySet()) {
                    httpPost.addHeader(key, header.get(key));
                }
            }
            if (pairs != null && pairs.size() > 0) {
                httpPost.setEntity(new UrlEncodedFormEntity(pairs, CHARSET));
            }
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpPost.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, charset);
            }
            EntityUtils.consume(entity);
            return result;
        } catch (Exception e) {
            LOG.warn("发送请求失败:{}", Throwables.getStackTraceAsString(e));
        } finally {
            closeResponse(response);
            closeHttpClient(httpClient);
        }
        return null;
    }

    /**
     * JSON方式post请求方式
     * 
     * @param url
     * @param params
     * @param charset
     * @param header
     * @return
     */
    private static String doPost(String url, String params, Map<String, String> header, String charset) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        CloseableHttpClient httpClient = getClientByUrl(url);
        CloseableHttpResponse response = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            StringEntity s = new StringEntity(params, ContentType.APPLICATION_JSON);
            s.setContentEncoding(charset);
            s.setContentType("application/json");
            httpPost.setEntity(s);
            //如果有请求头参数，添加进header中
            if (null != header && !header.isEmpty()) {
                for (String key : header.keySet()) {
                    httpPost.addHeader(key, header.get(key));
                }
            }
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpPost.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, charset);
            }
            EntityUtils.consume(entity);
            return result;
        } catch (Exception e) {
            LOG.warn("发送请求失败:{}", Throwables.getStackTraceAsString(e));
        } finally {
            closeResponse(response);
            closeHttpClient(httpClient);
        }
        return null;
    }

    private static void closeResponse(CloseableHttpResponse response) {
        try {
            if (null != response) {
                response.close();
            }
        } catch (IOException e) {
            LOG.warn("close httpClient :{}", Throwables.getStackTraceAsString(e));
        }
    }

    private static void closeHttpClient(CloseableHttpClient httpClient) {
        try {
            if (null != httpClient) {
                httpClient.close();
            }
        } catch (IOException e) {
            LOG.warn("close httpClient :{}", Throwables.getStackTraceAsString(e));
        }
    }

    private static CloseableHttpClient getClientByUrl(String url) {
        if (StringUtils.isNotBlank(url) && url.startsWith("https")) {
            return createSSLClientDefault();
        } else {
            return HttpClients.createDefault();
        }
    }
}
